ひとりNavigation API Advent Calendar 20日目
https://gyazo.com/9491100563642235bcac08230f5dda4c
これはひとりNavigation API Advent Calendarの20日目です。
Navigation APIのセキュリティにまつわる点を見ていきます。
Security and Privacy Questionnaire Answersの内容について
Self-Review Questionnaire: Security and Privacy
これはWebの新しい技術(APIや機能)を開発する際に、その技術がユーザーの安全やプライバシーを損なわないかを設計者が自らが確認するためのチェックシート
これに基づいた回答
Navigation API: セキュリティとプライバシーに関するセルフアンケートへの回答
以下は、W3C TAGのセキュリティおよびプライバシーのセルフレビューアンケートに対する回答です。
この機能はどのような情報をWebサイトやその他の当事者に公開する可能性がありますか?また、その公開はどのような目的で必要ですか?
関連する情報として、以下の2点が考えられます。
historyEntry.state プロパティを通じた情報の公開
以前にNavigation APIを通じて保存された情報が、再びNavigation APIを介して公開されます。これは、アプリケーションやUIの状態を履歴エントリに関連付けるために必要です。なお、このAPIを通じて公開される履歴エントリは、Same Originかつ連続したドキュメントに限定されているため、これは新しい機能(権限)ではありません。
Maps イベントを通じたナビゲーション情報の公開
これは、アプリケーションロジックの集約やシングルページナビゲーションパターンの実装のためにナビゲーションをインターセプトするという、このAPIの主要な目標を達成するために必要です。ここで公開される情報は、グローバルな click ハンドラや beforeunload ハンドラーなど、現在でも(より使いにくい手段ではありますが)収集可能なものと同じです。
この仕様の機能は、意図された用途を実現するために必要な最小限の情報のみを公開していますか?
はい。
この仕様の機能は、個人情報、個人を特定できる情報(PII)、またはそれらから派生した情報をどのように扱いますか?
それらの情報は利用しません。
この仕様の機能は、機密情報をどのように扱いますか?
それらの情報は利用しません。
この仕様の機能は、ブラウジングセッションをまたいで永続するオリジン固有の新しい状態を導入しますか?
いいえ
historyEntry.state における永続的な状態は、特にセッション履歴エントリにスコープされており、それらはブラウジングセッション内に限定されます。
この仕様の機能は、基盤となるプラットフォームに関する情報をオリジンに公開しますか?
いいえ。
この仕様の機能は、オリジンに対してユーザーデバイスのセンサーへのアクセスを許可しますか?
いいえ。
この仕様の機能は、どのようなデータをオリジンに公開しますか?また、同一または異なるコンテキストにおいて、他の機能によって公開されるデータと同一であるものがあれば、それについても記載してください。
この質問はオリジンを跨いだ情報の露出に関するものと思われますが、本機能ではそのような露出は発生しません。
この仕様の機能は、新しいスクリプトの実行または読み込みメカニズムを可能にしますか?
いいえ。
この仕様は、オリジンに対して他のデバイスへのアクセスを許可しますか?
いいえ。
この仕様の機能は、ユーザーエージェント(ブラウザ)のネイティブUIに対する制御を、ある程度オリジンに許可しますか?
現在可能な範囲を超えて許可することはありません。
URLバーや戻るボタンなどのネイティブUIを介したナビゲーションは、キャンセル可能な Maps イベントを発生させません。詳細については、「ナビゲーションの監視とインターセプト」セクションの悪用防止に関する議論、および「戻るボタンとユーザーエージェントUIへの影響」セクションを参照してください。
このAPIは、Maps イベントをインターセプトし、通常はドキュメント間のナビゲーション(クロスドキュメント)になるものを同一ドキュメント内のナビゲーション(セームドキュメント)に変換することで、ブラウザのURLバーの内容を更新する機能をページに提供します。しかし、この能力は history.pushState() と同様に制限されています。つまり、遷移先の新しいURLは、現在のURLとパス(path)、クエリ(query)、フラグメント(fragment)の部分のみが異なるものでなければなりません。
したがって、これを利用してURLを偽装することはできません。
例えば、https://evil.example/ から https://good.example/ へのナビゲーションに対して、https://evil.example/ 側のカスタムコンテンツを応答させることは不可能です。URLのホスト部分が異なるため、このようなナビゲーションを https://evil.example/ がインターセプトすることはできません。
言い換えれば、URLバーに https://good.example/ と表示されている場合、その表示内容をコントロールできるのは https://good.example/ だけです。
この仕様の機能は、どのような一時的な識別子を生成、またはWebに公開しますか?
各履歴エントリには、自動生成された key および id プロパティが関連付けられており、これらはランダムなUUIDです。これは問題ないと考えています。詳細はメインの解説書内の議論を参照してください。
この仕様は、ファーストパーティとサードパーティのコンテキストにおける動作をどのように区別していますか?
特に区別していません
この仕様の設計によるブラウジングコンテキスト、ブラウジングセッション、およびオリジンごとの分離は、各当事者が独自のNavigation APIのhistoryEntryのリストを取得することを意味します。各リストは一律に動作し、その当事者に関する情報のみを提供します。
この仕様の機能は、ブラウザのプライベートブラウジングまたはシークレットモードのコンテキストでどのように動作しますか?
おそらく違いはありません。もし違いがあるとすれば、それはブラウザがそのようなモードでセッション履歴をどのようにモデル化しているかという既存の違いに起因するものですが、現時点で認識している違いはありません。
この仕様には「セキュリティ上の考慮事項」と「プライバシー上の考慮事項」の両方のセクションがありますか?
はい。
この仕様の機能は、デフォルトのセキュリティ特性を低下させますか?
いいえ。
---
yamanoku.icon Navigation API自体はセキュリティの懸念はないようにしてるが、サイトそのものが脆弱だったりサードパーティ製ライブラリが混入されるといくらでもおかしいことはされてしまうのよね
Navigation APIのintercept()は強力な機能ではあるけど、これは悪用されると現状よりひどいことは起きるなと感じている
事前にどう防ぐといいのだろうか?
Trusted Typesを使う
code:js
// ライブラリ内部でポリシーを定義
const policy = window.trustedTypes?.createPolicy('my-router-policy', {
createHTML: (html) => DOMPurify.sanitize(html) // DOMPurifyなどで洗浄
});
navigation.addEventListener('navigate', (event) => {
event.intercept({
async handler() {
const content = await fetchPageContent(event.destination.url);
// 安全なHTMLオブジェクトとして流し込む
document.getElementById('app').innerHTML = policy
? policy.createHTML(content)
: content;
}
});
});
実際にはinnerHTMLで入れ込むというのもまずないと思うが…
HTTPでのContent-Security-Policyの設定も有効
Content-Security-Policy: require-trusted-types-for 'script';
あるいはmeta要素より注入する
<meta http-equiv="content-security-policy" content="require-trusted-types-for 'script'" />
2025-12-20時点でFirefoxは有効ではないが…
canInterceptがfalseの場合に早期return
isTrustedがfalseの場合も想定しておく
その場合intercept()例外としてSecurityErrorを投げる仕様になっている
---
セキュリティとは逸れるけど戻るボタン制御のWeb広告表示みたいなのもNavigation APIで操作されるようになるのかなぁ…となっています